use std::{env, fs, path};
use std::fmt::Error;

use actix_web::{App, HttpServer, web};
use dotenv::dotenv;
use log::info;
use sea_orm::Database;

use common::config::{InitYamlConf, SystemConf};
use common::ctx::{set_db, set_db_by_key, set_dict_conf, set_system_conf};
use common::error::MyError;
use common::state::AppState;
use migration::{Migrator, MigratorTrait};
use security::ctx::set_auth_conf;
use security::wtt;
use service::auth_service;
use service::dict::DictGroupService;

use crate::routes::general_routes;

mod controller;
mod routes;

#[actix_web::main]
async fn start() -> Result<(), MyError> {
    let system_conf = init_conf().unwrap();
    let clone_system_conf = system_conf.clone();
    set_system_conf(Some(system_conf.clone()))?;
    info!(">>>>>>>>>> 初始化数据库连接 <<<<<<<<<< ");
    let db = Database::connect(clone_system_conf.database_url)
        .await?;

    info!(">>>>>>>>>> 初始化主数据库表连接 <<<<<<<<<<");
    set_db(Some(db.clone()))?;
    Migrator::up(&db, None).await?;
    info!(">>>>>>>>>> 初始化其他数据库连接 <<<<<<<<<<");
    let db_conf = system_conf.database.clone();
    for key in db_conf.databases {
        let database_url = format!("{}://{}:{}@{}:{}/{}{}",
                                   db_conf.database_type,
                                   db_conf.username,
                                   db_conf.password,
                                   db_conf.host,
                                   db_conf.port,
                                   key,
                                   db_conf.param);
        info!("{}：{}", key, database_url);
        let db = Database::connect(database_url).await?;
        set_db_by_key(key.clone(), Some(db))?;
    }

    info!(">>>>>>>>>> 初始化字典信息 <<<<<<<<<<");
    let dict_conf = DictGroupService::init_dict_conf().await?;
    let _ = set_dict_conf(Option::from(dict_conf));

    info!(">>>>>>>>>> 初始化鉴权配置 <<<<<<<<<<");
    let auth_conf = auth_service::init_auth_conf().await?;
    let _ = set_auth_conf(Option::from(auth_conf));

    info!(">>>>>>>>>> 初始化全局共享数据 <<<<<<<<<<");
    let shared_data = web::Data::new(AppState {
        health_check_response: "OK.".to_string(),
        db: db.clone(),
        system_conf: system_conf.clone(),
    });

    let app = move || {
        App::new()
            .wrap(wtt::Auth)
            .app_data(shared_data.clone())
            .configure(general_routes)
    };
    info!("Starting server at {}", clone_system_conf.server_url);

    // 使用 join! 宏来同时运行异步任务
    // let (http_server, socks5_handle) = tokio::join!(
    //     async {
    //         HttpServer::new(app)
    //             .bind(clone_system_conf.server_url)?
    //             .run()
    //             .await
    //     },
    //     async {
    //         socks5::start(system_conf.clone()).await
    //     }
    // );

    // 等待两个任务都完成
    // let _ = http_server;
    // let _ = socks5_handle;
    HttpServer::new(app)
        .bind(clone_system_conf.server_url)?
        .run()
        .await?;
    Ok(())
}

fn init_conf() -> Result<SystemConf, Error> {
    println!(">>>>>>>>>> 读取配置文件 <<<<<<<<<<");
    let yaml_path = path::Path::new("config.yaml");
    let yaml_string = fs::read_to_string(yaml_path);
    let mut init_conf: InitYamlConf =
        serde_yaml::from_str(yaml_string.unwrap().as_str()).expect("读取配置文件失败");

    println!(">>>>>>>>>> 加载环境变量 <<<<<<<<<<");
    dotenv().ok();

    println!(">>>>>>>>>> 设置IP端口配置 <<<<<<<<<<");
    let env_host = env::var("HOST");
    if env_host.is_ok() {
        println!(">>>>>>>>>> 检测到环境变量设置了服务启动IP [HOST] , 替换配置 <<<<<<<<<<");
        init_conf.server.host = env_host.unwrap();
    }

    let env_port = env::var("PORT");
    if env_port.is_ok() {
        println!(">>>>>>>>>> 检测到环境变量设置了服务启动端口 [PORT] , 替换配置 <<<<<<<<<<");
        init_conf.server.port = env_port.unwrap();
    }

    let mut sys_conf = SystemConf {
        rust_log_level: init_conf.rust_log_level,
        server_url: format!("{}:{}", init_conf.server.host, init_conf.server.port),
        socks_url: format!("{}:{}", init_conf.socks.host, init_conf.socks.port),
        database_url: init_conf.database_url,
        email: init_conf.email,
        version: init_conf.version,
        mode: init_conf.mode,
        database: init_conf.database,
    };

    println!(">>>>>>>>>> 设置日志等级 <<<<<<<<<<");
    let env_rust_log = env::var("RUST_LOG");
    if env_rust_log.is_ok() {
        println!(">>>>>>>>>> 检测到环境变量设置了日志等级 [RUST_LOG] , 替换配置");
        sys_conf.rust_log_level = env_rust_log.unwrap();
    }
    env::set_var("RUST_LOG", sys_conf.rust_log_level.clone());
    env_logger::init();

    println!(">>>>>>>>>> 设置数据库连接 <<<<<<<<<<");
    let env_database_url = env::var("DATABASE_URL");
    if env_database_url.is_ok() {
        println!(">>>>>>>>>> 检测到环境变量设置了数据库连接 [DATABASE_URL] , 替换配置 <<<<<<<<<<");
        sys_conf.database_url = env_database_url.unwrap();
    }

    Ok(sys_conf)
}

pub fn main() {
    let result = start();

    if let Some(err) = result.err() {
        info!("Error: {err}");
    }
}
